<template>
  <van-text-area
    v-model="fieldLabel"
    :disabled="disabled"
    :label="label"
    :label-align="labelAlign"
    :placeholder="readonly ? '' : placeholder || `请选择${label}`"
    :required="required"
    :rules="rules"
    readonly
    @click="!readonly && !disabled && (showPicker = true)"
  />
  <div></div>
  <van-popup v-model:show="showPicker" :lazy-render="false" position="bottom" round teleport="body" @open="onOpen">
    <van-cell-group v-if="search && !tree" inset>
      <div style="display: flex">
        <van-search
          v-model="searchValue"
          :clearable="false"
          :placeholder="`请输入${label}名称`"
          style="margin-right: 10vw"
        />
        <van-icon
          color="#1989fa"
          name="close"
          style="margin-top: auto; margin-bottom: auto"
          @click="showPicker = false"
        />
      </div>
    </van-cell-group>
    <template v-if="isNotEmpty(selectOptions)">
      <van-tree-select
        v-if="tree"
        v-model:active-id="treePickValue"
        v-model:main-active-index="mainActiveId"
        :items="selectOptions"
        style="height: 60vh; overflow: auto"
      />
      <van-checkbox-group v-else ref="checkboxGroup" v-model="checked">
        <van-cell-group inset style="height: 40vh; overflow: auto">
          <van-cell
            v-for="(item, index) in selectOptions"
            :key="index"
            :title="item[props.columnsFieldNames.text]"
            clickable
            @click="toggle(index)"
          >
            <template #right-icon>
              <van-checkbox
                :ref="(el: any) => (checkboxRefs[index] = el)"
                :name="item[props.columnsFieldNames.text]"
                @click.stop
              />
            </template>
          </van-cell>
        </van-cell-group>
      </van-checkbox-group>
    </template>
    <EmptyContent v-else />
    <div>
      <van-cell-group inset>
        <van-cell>
          <template v-if="!tree">
            <van-row justify="space-between">
              <van-col span="11">
                <van-button block size="small" type="success" @click="checkAll">全选</van-button>
              </van-col>
              <van-col span="11">
                <van-button block size="small" @click="toggleAll">反选</van-button>
              </van-col>
            </van-row>
          </template>
        </van-cell>
      </van-cell-group>
      <div class="van-hairline--top van-dialog__footer">
        <button
          class="van-button van-button--default van-button--large van-dialog__cancel"
          type="button"
          @click="showPicker = false"
        >
          <div class="van-button__content">
            <span class="van-button__text">取消</span>
          </div>
        </button>
        <button
          class="van-button van-button--default van-button--large van-dialog__confirm van-hairline--left"
          type="button"
          @click="onConfirm"
        >
          <div class="van-button__content">
            <span class="van-button__text">确认</span>
          </div>
        </button>
      </div>
    </div>
  </van-popup>
</template>

<script lang="ts" setup>
import { CheckboxGroupInstance, CheckboxInstance, FieldTextAlign } from 'vant'
import _, { isEmpty } from 'lodash'
import { QUERY_INTERVAL } from '@/framework/constant'
import { onBeforeMount, Ref } from 'vue'
import { useDictStore, useTreeStore } from '@/framework/store/common'
import VanTextArea from '@/framework/components/Vant/VanTextArea.vue'
import { getAllNodes, isNotEmpty } from '@/framework/utils/common'
import EmptyContent from '@/framework/components/EmptyContent/index.vue'

const props = withDefaults(
  defineProps<{
    modelValue: Array<any> | null
    label: string
    dict?: string
    columns?: any
    rules?: Array<any>
    required?: boolean
    labelAlign?: FieldTextAlign
    search?: boolean
    pageSize?: number
    columnsFieldNames?: any
    readonly?: boolean
    onlyShowSelect?: boolean
    placeholder?: string
    disabled?: boolean
    tree?: boolean
  }>(),
  {
    rules: undefined,
    dict: undefined,
    columns: [],
    labelAlign: 'top',
    search: true,
    pageSize: 30,
    columnsFieldNames: { text: 'label', value: 'value', children: 'children' },
    readonly: false,
    onlyShowSelect: false,
    placeholder: '',
    disabled: false,
    tree: false
  }
)
const emit = defineEmits<{
  (e: 'update:modelValue', value: Array<any> | null): void
  (e: 'getSelectOptions', value: string, pageSize: number): void
}>()
const dictStore = useDictStore()
const treeStore = useTreeStore()
const showPicker: Ref<boolean> = ref(false)
const {
  columns,
  label,
  dict,
  modelValue,
  rules,
  required,
  labelAlign,
  search,
  pageSize,
  readonly,
  onlyShowSelect,
  disabled,
  tree
} = toRefs(props)
const fieldLabel: Ref<string | null> = ref('')
const searchValue = ref('')
const selectOptions = ref(columns.value)
const dictOptions = ref([])
const treePickValue = ref(modelValue.value)
const mainActiveId = ref()
const checked: Ref<Array<string>> = ref([])
const checkboxRefs: Ref<Array<CheckboxInstance>> = ref([])
const checkboxGroup: Ref<CheckboxGroupInstance | null> = ref(null)
const valueLabelMap = new Map()
const labelValueMap = new Map()

const updateDisplay = (options: any) => {
  if (tree.value) {
    getAllNodes(options, (option: any) => {
      valueLabelMap.set(option[props.columnsFieldNames.value], option[props.columnsFieldNames.text])
      labelValueMap.set(option[props.columnsFieldNames.text], option[props.columnsFieldNames.value])
    })
  } else {
    options.forEach((option: any) => {
      valueLabelMap.set(option[props.columnsFieldNames.value], option[props.columnsFieldNames.text])
      labelValueMap.set(option[props.columnsFieldNames.text], option[props.columnsFieldNames.value])
    })
  }

  const displayList = [] as Array<any>
  if (isEmpty(modelValue.value)) {
    fieldLabel.value = ''
  } else {
    modelValue.value?.forEach((value: any) => {
      const label = valueLabelMap.get(value)
      displayList.push(label)
    })
    isNotEmpty(displayList) && (fieldLabel.value = displayList.join('，'))
  }
}

watch(
  () => dictOptions.value,
  () => {
    selectOptions.value = dictOptions.value
    updateDisplay(dictOptions.value)
  },
  {
    immediate: true
  }
)
watch(
  () => columns.value,
  () => {
    selectOptions.value = columns.value.slice(0, 200)
    updateDisplay(columns.value)
  },
  {
    immediate: true
  }
)
watch(
  () => modelValue.value,
  () => {
    if (isEmpty(modelValue.value)) {
      fieldLabel.value = ''
    }
    updateDisplay([])
  },
  {
    immediate: true
  }
)
watch(
  () => searchValue.value,
  _.debounce(() => {
    if (dict.value) {
      if (isEmpty(searchValue.value)) dictStore.getDict(dict.value, selectOptions)
      else
        selectOptions.value = dictOptions.value.filter(
          (option: any) => option[props.columnsFieldNames.text].indexOf(searchValue.value) !== -1
        )
    }
    emit('getSelectOptions', searchValue.value, pageSize.value)
  }, QUERY_INTERVAL)
)

const onConfirm = () => {
  searchValue.value = ''
  let dataList = [] as Array<any>
  if (tree.value && treePickValue.value) {
    const fieldData = [] as Array<any>
    treePickValue.value.forEach((check: any) => {
      fieldData.push(valueLabelMap.get(check))
      dataList.push(check)
    })
    fieldLabel.value = fieldData.join('，')
  } else {
    fieldLabel.value = checked.value.join('，')
    checked.value.forEach((check: any) => {
      dataList.push(labelValueMap.get(check))
    })
  }
  emit('update:modelValue', dataList)
  showPicker.value = false
}

const onOpen = () => {
  searchValue.value = ''
  if (onlyShowSelect.value) {
    selectOptions.value.length = 0
    modelValue.value?.forEach((value: any) => {
      const label = valueLabelMap.get(value)
      selectOptions.value.push({
        [props.columnsFieldNames.value]: value,
        [props.columnsFieldNames.text]: label
      })
    })
  } else {
    emit('getSelectOptions', searchValue.value, pageSize.value)
  }
  checked.value.length = 0
  modelValue.value?.forEach((value: any) => {
    checked.value.push(valueLabelMap.get(value))
  })
}

onBeforeMount(() => {
  if (dict.value) {
    if (tree.value) {
      treeStore.getTree(dict.value, dictOptions)
    } else {
      dictStore.getDict(dict.value, dictOptions)
    }
  }
})

const toggle = (index: number) => checkboxRefs.value[index].toggle()
const checkAll = () => checkboxGroup.value && checkboxGroup.value.toggleAll(true)
const toggleAll = () => checkboxGroup.value && checkboxGroup.value.toggleAll()
</script>
